package cn.code.code.wiget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.ArrayList;

import cn.code.code.util.Logger;

public class DemoView2 extends View {

    private Paint mPaint;

    public DemoView2(Context context) {
        this(context, null);
    }

    public DemoView2(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DemoView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public DemoView2(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    //初始化画笔Paint
    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    }


    @Override
    protected void onDraw(Canvas canvas) {

        PointF point1=new PointF(100,100);
        PointF point2=new PointF(200,150);
        PointF point3=new PointF(350,50);
        PointF point4=new PointF(500,200);
        PointF point5=new PointF(650,125);

        ArrayList<PointF> points=new ArrayList<>();
        points.add(point1);
        points.add(point2);
        points.add(point3);
        points.add(point4);
        points.add(point5);

        drawSrcPoints(points,canvas,mPaint);

        ArrayList<ControlPoints> controlPoints=getControlPoints(points);
        drawControlPoints(controlPoints,canvas,mPaint);

        drawBeisaier(points,controlPoints,canvas,mPaint);

    }
    private void drawBeisaier(ArrayList<PointF> points, ArrayList<ControlPoints> controlPoints, Canvas canvas, Paint mPaint) {

        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.STROKE);
        Path path=new Path();

        for (int i = 0; i < points.size(); i++) {
            if (i==0){
                path.moveTo(points.get(i).x,points.get(i).y);
            }else if (i==points.size()-1){
                path.rCubicTo(50,50,50,50,50,50);
            }else{
                PointF firstControlPoint = controlPoints.get(i - 1).getRightControlPoint();
                PointF secondControlPoint = controlPoints.get(i).getLeftControlPoint();
                path.cubicTo(firstControlPoint.x,firstControlPoint.y,secondControlPoint.x,secondControlPoint.y,points.get(i).x,points.get(i).y);
            }
        }
        canvas.drawPath(path,mPaint);
    }

    private void drawControlPoints(ArrayList<ControlPoints> controlPoints, Canvas canvas, Paint mPaint) {
        mPaint.setColor(Color.YELLOW);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(1);

        for (ControlPoints controlPoint : controlPoints) {
             canvas.drawCircle(controlPoint.getLeftControlPoint().x,controlPoint.getLeftControlPoint().y,4,mPaint);
             canvas.drawCircle(controlPoint.getRightControlPoint().x,controlPoint.getRightControlPoint().y,4,mPaint);
             canvas.drawLine(controlPoint.getLeftControlPoint().x,controlPoint.getLeftControlPoint().y,controlPoint.getRightControlPoint().x,controlPoint.getRightControlPoint().y,mPaint);
        }

    }

    private void drawSrcPoints(ArrayList<PointF> points, Canvas canvas, Paint mPaint) {
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);
        for (PointF point : points) {
            canvas.drawCircle(point.x,point.y,4,mPaint);
        }
    }

    //获取所有控制点，一个点对应两个控制点
    private ArrayList<ControlPoints> getControlPoints(ArrayList<PointF> points) {

        //确保至少有两个点，才能画曲线
        if (points.size()<2){
            return null;
        }

        ArrayList<ControlPoints> controlPoints=new ArrayList<>();

        PointF leftCenterPoint,rightCenterPoint;
        for (int i = 0; i <points.size(); i++) {
            if (i==0){
                rightCenterPoint = getCenterPoint(points.get(i+1), points.get(i));
                // 在第一个点前补一个与后一个中点对应的一个镜像中点leftCenterPoint
                leftCenterPoint=new PointF();
                leftCenterPoint.x=points.get(i).x-(rightCenterPoint.x-points.get(i).x);
                leftCenterPoint.y=rightCenterPoint.y;
            }else if (i==points.size()-1){
                leftCenterPoint = getCenterPoint(points.get(i), points.get(i - 1));
                // 在最后补一个与前中点对应的一个镜像中点rightCenterPoint
                rightCenterPoint=new PointF();
                rightCenterPoint.x=points.get(i).x-leftCenterPoint.x+points.get(i).x;
                rightCenterPoint.y=leftCenterPoint.y;
            }else{
                leftCenterPoint = getCenterPoint(points.get(i), points.get(i - 1));
                rightCenterPoint = getCenterPoint(points.get(i), points.get(i + 1));
            }

            PointF centerPoint = getCenterPoint(rightCenterPoint, leftCenterPoint);
            float dx=points.get(i).x-centerPoint.x;
            float dy=points.get(i).y-centerPoint.y;

            //左边的控制点
            PointF leftControlPoint=new PointF();
            leftControlPoint.x=leftCenterPoint.x+dx;
            leftControlPoint.y=leftCenterPoint.y+dy;

            //右边的控制点
            PointF rightControlPoint=new PointF();
            rightControlPoint.x=rightCenterPoint.x+dx;
            rightControlPoint.y=rightCenterPoint.y+dy;

            controlPoints.add(new ControlPoints(leftControlPoint,rightControlPoint));

        }
        return controlPoints;
    }

    private PointF getCenterPoint(PointF endPoint, PointF startPoint) {
        PointF centerPoint=new PointF();
        centerPoint.x=(endPoint.x+startPoint.x)/2f;
        centerPoint.y=(endPoint.y+startPoint.y)/2f;
        return centerPoint;
    }

    //根据起点、结束点、波峰/波谷点，计算贝塞尔曲线的控制点
    private PointF calculateControlPont(PointF start, PointF end, PointF wave) {

//        float t=(wave.x-start.x)/(end.x-start.x);

        double atan = (wave.y - start.y) / (wave.x - start.x);

        float tt=0.5f;

//        float t= (float) (tt*Math.atan(Math.tan(atan)/180*Math.PI));
        float t= 0.5f;

        Logger.e(t+"    "+atan);

        PointF point=new PointF();
        point.x= (wave.x-t*t*end.x-(1-t)*(1-t)*start.x)/(float) (2*(1-t)*t);
        point.y=(wave.y-t*t*end.y-(1-t)*(1-t)*start.y)/(float)( 2*(1-t)*t);
        return point;
    }

    public class ControlPoints{
        private PointF leftControlPoint;
        private PointF rightControlPoint;

        public ControlPoints(PointF leftControlPoint, PointF rightControlPoint) {
            this.leftControlPoint = leftControlPoint;
            this.rightControlPoint = rightControlPoint;
        }

        public PointF getLeftControlPoint() {
            return leftControlPoint;
        }

        public void setLeftControlPoint(PointF leftControlPoint) {
            this.leftControlPoint = leftControlPoint;
        }

        public PointF getRightControlPoint() {
            return rightControlPoint;
        }

        public void setRightControlPoint(PointF rightControlPoint) {
            this.rightControlPoint = rightControlPoint;
        }

        @NonNull
        @Override
        public String toString() {
            return "leftControlPoint="+this.leftControlPoint.toString()+"    rightControlPoint="+this.rightControlPoint.toString();
        }
    }


}
